package org.unidata.mdm.draft.context;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

import javax.annotation.Nullable;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.unidata.mdm.system.context.AbstractCompositeRequestContext;

/**
 * @author Mikhail Mikhailov on Sep 18, 2020
 */
public abstract class AbstractDraftFieldsContext extends AbstractDraftDataContext {
    /**
     * GSVUID.
     */
    private static final long serialVersionUID = -6111969031432991565L;
    /**
     * The draft provider ID.
     */
    private final String provider;
    /**
     * Subject id.
     */
    private final String subjectId;
    /**
     * Current owner.
     */
    private final String owner;
    /**
     * An arbitrary set of searchable tags.
     */
    private final Set<String> tags;
    /**
     * Constructor.
     * @param b
     */
    protected AbstractDraftFieldsContext(AbstractDraftFieldsContextBuilder<?> b) {
        super(b);
        this.provider = b.provider;
        this.subjectId = b.subjectId;
        this.owner = b.owner;
        this.tags = b.tags;
    }
    /**
     * Gets draft provider id.
     * @return the id
     */
    public String getProvider() {
        return provider;
    }
    /**
     * Gets subject id.
     * @return subject id
     */
    public String getSubjectId() {
        return subjectId;
    }
    /**
     * Gets owner user name
     * @return user name
     */
    public String getOwner() {
        return owner;
    }
    /**
     * An arbitrary set of searchable tags.
     * @return set of tags
     */
    public Set<String> getTags() {
        return Objects.isNull(tags) ? Collections.emptySet() : tags;
    }
    /**
     * Returns tags as strings array.
     * NOTE: if no tags specified, it will return null so it has to be checked!
     * @return tags as string array or null, if no tags specified
     */
    @Nullable
    public String[] getTagsAsArray() {
        return CollectionUtils.isEmpty(tags) ? null : tags.toArray(String[]::new);
    }
    /**
     * @author Mikhail Mikhailov on Sep 16, 2020
     * Builder.
     */
    public abstract static class AbstractDraftFieldsContextBuilder<X extends AbstractDraftFieldsContextBuilder<X>> extends AbstractDraftBaseContextBuilder<X> {
        /**
         * The draft provider ID.
         */
        private String provider;
        /**
         * Subject id.
         */
        private String subjectId;
        /**
         * Current owner.
         */
        private String owner;
        /**
         * An arbitrary set of searchable tags.
         */
        private Set<String> tags;
        /**
         * Constructor.
         * @param other the context to copy fields from
         */
        protected AbstractDraftFieldsContextBuilder(AbstractCompositeRequestContext other) {
            super(other);
        }
        /**
         * Constructor.
         */
        protected AbstractDraftFieldsContextBuilder() {
            super();
        }
        /**
         * Sets draft provider id.
         * @param provider the id
         * @return self
         */
        public X provider(String provider) {
            this.provider = provider;
            return self();
        }
        /**
         * Sets subject id
         * @param entityId the subject id
         * @return self
         */
        public X subjectId(String entityId) {
            this.subjectId = entityId;
            return self();
        }
        /**
         * Sets the owner's username
         * @param draftOwner the owner user name
         * @return self
         */
        public X owner(String draftOwner) {
            this.owner = draftOwner;
            return self();
        }
        /**
         * Adds tag.
         * @param tag the tag
         * @return self
         */
        public X tags(String... tags) {
            if (ArrayUtils.isNotEmpty(tags)) {
                return tags(Arrays.asList(tags));
            }
            return self();
        }
        /**
         * Adds tag.
         * @param tag the tag
         * @return self
         */
        public X tags(Collection<String> tags) {
            if (CollectionUtils.isNotEmpty(tags)) {
                for (String t : tags) {

                    if (Objects.isNull(t)) {
                        continue;
                    }

                    if (Objects.isNull(this.tags)) {
                        this.tags = new HashSet<>();
                    }

                    this.tags.add(t);
                }
            }
            return self();
        }
    }
}
